package org.jeecg.modules.shiro.authc.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.system.util.SakurUtils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Map;

/**
 * 动态数据源实现类
 * @author sakur
 * @since 2022/11/14
 */
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {

    private Map<Object, Object> dynamicTargetDataSources;

    @Resource
    private SakurUtils sakurUtils;

    /**
     * 决定使用哪个数据源之前需要把多个数据源的信息以及默认数据源信息配置好
     *
     * @param defaultTargetDataSource 默认数据源
     * @param targetDataSources       目标数据源
     */
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        setDefaultTargetDataSource(defaultTargetDataSource);
        setTargetDataSources(targetDataSources);
        this.dynamicTargetDataSources = targetDataSources;
        super.afterPropertiesSet();
    }

    public DynamicDataSource() {
    }

    /**
     * 如果不希望数据源在启动配置时就加载好，可以定制这个方法，从任何你希望的地方读取并返回数据源
     * 比如从数据库、文件、外部接口等读取数据源信息，并最终返回一个DataSource实现类对象即可
     */
    @Override
    protected DataSource determineTargetDataSource() {
        return super.determineTargetDataSource();
    }

    /**
     * 如果希望所有数据源在启动配置时就加载好，这里通过设置数据源Key值来切换数据，定制这个方法
     *
     * 实现数据源切换要扩展的方法，该方法的返回值就是项目中所要用的DataSource的key值，
     * 拿到该key后就可以在resolvedDataSource中取出对应的DataSource，如果key找不到对应的DataSource就使用默认的数据源。
     */
    @Override
    protected Object determineCurrentLookupKey() {
        String dataSourceName = DynamicDataSourceContextHolder.getDataSourceKey();
        if (!StringUtils.isEmpty(dataSourceName)) {
            Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
            if (dynamicTargetDataSources2.containsKey(dataSourceName)) {
                log.info("当前数据源为：" + dataSourceName);
            } else {
                log.info("不存在的数据源："+ dataSourceName);
            }
        } else {
            log.info("当前数据源为：默认数据源");
        }
        return dataSourceName;
    }

    /**
     * 设置默认数据源
     * @param defaultDataSource Object
     */
    @Override
    public void setDefaultTargetDataSource(Object defaultDataSource) {
        super.setDefaultTargetDataSource(defaultDataSource);
    }

    /**
     * 设置数据源
     * @param dataSources Map<Object, Object>
     */
    @Override
    public void setTargetDataSources(Map<Object, Object> dataSources) {

        super.setTargetDataSources(dataSources);

        this.dynamicTargetDataSources = dataSources;

        // 将数据源的 key 放到数据源上下文的 key 集合中，用于切换时判断数据源是否有效
        DynamicDataSourceContextHolder.addDataSourceKeys(dataSources.keySet());
    }

    /**
     * 初始化数据源
     * @param k tenant_key
     * @param url jbbc connect url
     * @param u username
     * @param p password
     */
    public void setDataSources(String k, String url, String u, String p) {
        try {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(sakurUtils.driverClassName);
            dataSource.setUrl(url);
            dataSource.setUsername(u);
            dataSource.setPassword(p);
            // 测试连接
            dataSource.getConnection();

            this.dynamicTargetDataSources.put(k, dataSource);
            setTargetDataSources(this.dynamicTargetDataSources);
            super.afterPropertiesSet();
            log.info("数据源初始化成功------>" + k);
        } catch (Exception e) {
            throw new IllegalStateException("[" + k + "]" + "：数据源连接不上， 可能是连接参数有误！");
        }
    }

}
